/* Copyright 2013-2015 www.snakerflow.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.snaker.engine.handlers.impl;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.snaker.engine.SnakerEngine;
import org.snaker.engine.SnakerException;
import org.snaker.engine.access.QueryFilter;
import org.snaker.engine.core.Execution;
import org.snaker.engine.entity.Order;
import org.snaker.engine.entity.Process;
import org.snaker.engine.handlers.IHandler;
import org.snaker.engine.helper.AssertHelper;
import org.snaker.engine.model.SubProcessModel;

/**
 * 启动子流程的处理器
 * 
 * @author yuqs
 * @since 1.0
 */
public class StartSubProcessHandler implements IHandler {
    private SubProcessModel model;
    /**
     * 是否以future方式执行启动子流程任务
     */
    private boolean isFutureRunning = false;

    public StartSubProcessHandler(SubProcessModel model) {
        this.model = model;
    }

    public StartSubProcessHandler(SubProcessModel model, boolean isFutureRunning) {
        this.model = model;
        this.isFutureRunning = isFutureRunning;
    }

    /**
     * 子流程执行的处理
     */
    public void handle(Execution execution) {
        // 根据子流程模型名称获取子流程定义对象
        SnakerEngine engine = execution.getEngine();
        Process process = engine.process().getProcessByVersion(model.getProcessName(), model.getVersion());

        Execution child = execution.createSubExecution(execution, process, model.getName());
        Order order = null;
        if (isFutureRunning) {
            // 创建单个线程执行器来执行启动子流程的任务
            ExecutorService es = Executors.newSingleThreadExecutor();
            // 提交执行任务，并返回future
            Future<Order> future = es.submit(new ExecuteTask(execution, process, model.getName()));
            try {
                es.shutdown();
                order = future.get();
            } catch (InterruptedException e) {
                throw new SnakerException("创建子流程线程被强制终止执行", e.getCause());
            } catch (ExecutionException e) {
                throw new SnakerException("创建子流程线程执行异常.", e.getCause());
            }
        } else {
            order = engine.startInstanceByExecution(child);
        }
        AssertHelper.notNull(order, "子流程创建失败");
        execution.addTasks(engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId())));
    }

    /**
     * Future模式的任务执行。通过call返回任务结果集
     * 
     * @author yuqs
     * @since 1.0
     */
    class ExecuteTask implements Callable<Order> {
        private SnakerEngine engine;
        private Execution child;

        /**
         * 构造函数
         * 
         * @param execution
         * @param process
         * @param parentNodeName
         */
        public ExecuteTask(Execution execution, Process process, String parentNodeName) {
            this.engine = execution.getEngine();
            child = execution.createSubExecution(execution, process, parentNodeName);
        }

        public Order call() throws Exception {
            return engine.startInstanceByExecution(child);
        }
    }
}
